package com.egao.common.module.marketPush.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.egao.common.component.wechat.WeChatUtils;
import com.egao.common.core.Constants;
import com.egao.common.core.utils.ExcelUtils;
import com.egao.common.core.web.JsonResult;
import com.egao.common.core.web.PageParam;
import com.egao.common.module.marketPush.entity.MarketPush;
import com.egao.common.module.marketPush.entity.MarketPushRecord;
import com.egao.common.module.marketPush.mapper.MarketPushMapper;
import com.egao.common.module.marketPush.param.MarketPushParams;
import com.egao.common.module.marketPush.param.MarketPushRecordExport;
import com.egao.common.module.marketPush.service.MarketPushRecordService;
import com.egao.common.module.marketPush.service.MarketPushService;
import com.egao.common.module.student.entity.Student;
import com.egao.common.module.student.service.StudentService;
import com.egao.common.module.system.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lym
 * @date 2024/5/27 14:35
 */
@Service
public class MarketPushServiceImpl extends ServiceImpl<MarketPushMapper, MarketPush> implements MarketPushService {

    @Autowired
    private StudentService studentService;
    @Autowired
    private MarketPushRecordService marketPushRecordService;

    @Value("${servicem}")
    private String wechatUrl;

    /**
     * 推送成功
     */
    private final String SUCCESS = "0";
    /**
     * 推送失败
     */
    private final String FAIL = "1";

    @Override
    public List<MarketPush> listPage(PageParam<MarketPush> page) {
        String remark = page.getString("remark");
        String content = page.getString("content");
        PageParam<MarketPush> param = baseMapper.selectPage(page,
                new QueryWrapper<MarketPush>()
                        .like(!StrUtil.isBlank(remark), "remark", remark)
                        .like(!StrUtil.isBlank(content), "content", content)
                        .orderByDesc("create_time")
        );
        return param.getRecords();
    }

    @Override
    public List<String> listXh(MarketPushParams marketPushParams) {
        List<String> sex = marketPushParams.getSex();
        List<String> yearId = marketPushParams.getYearId();
        List<String> collegeCode = marketPushParams.getCollegeCode();
        List<String> majorCode = marketPushParams.getMajorCode();
        List<String> bjhm = marketPushParams.getBjhm();
        List<String> xl = marketPushParams.getXl();
        List<String> xw = marketPushParams.getXw();
        List<String> xwlb = marketPushParams.getXwlb();
        List<String> zzmm = marketPushParams.getZzmm();
        List<String> mz = marketPushParams.getMz();
        List<String> pyfs = marketPushParams.getPyfs();
        List<String> cxsy = marketPushParams.getCxsy();
        List<String> xxfs = marketPushParams.getXxfs();
        List<String> syszd = marketPushParams.getSyszd();
        List<String> zxjh = marketPushParams.getZxjh();
        List<String> xjzt = marketPushParams.getXjzt();
        List<String> jzbfdxbz = marketPushParams.getJzbfdxbz();
        List<String> knslb = marketPushParams.getKnslb();
        List<String> hyzk = marketPushParams.getHyzk();


        List<String> xhList = studentService.listObjs(new QueryWrapper<Student>()
                        .select("distinct(xh)")
                        .in(null != sex && !sex.isEmpty(), "xb", sex)
                        .in(null != yearId && !yearId.isEmpty(), "year_id", yearId)
                        .in(null != collegeCode && !collegeCode.isEmpty(), "college_code", collegeCode)
                        .in(null != majorCode && !majorCode.isEmpty(), "major_code", majorCode)
                        .in(null != bjhm && !bjhm.isEmpty(), "bjhm", bjhm)
                        .in(null != xl && !xl.isEmpty(), "xl", xl)
                        .in(null != xw && !xw.isEmpty(), "xw", xw)
                        .in(null != xwlb && !xwlb.isEmpty(), "xwlb", xwlb)
                        .in(null != zzmm && !zzmm.isEmpty(), "zzmm", zzmm)
                        .in(null != mz && !mz.isEmpty(), "mz", mz)
                        .in(null != pyfs && !pyfs.isEmpty(), "pyfs", pyfs)
                        .in(null != cxsy && !cxsy.isEmpty(), "cxsy", cxsy)
                        .in(null != xxfs && !xxfs.isEmpty(), "xxfs", xxfs)
                        .in(null != syszd && !syszd.isEmpty(), "syszd", syszd)
                        .in(null != zxjh && !zxjh.isEmpty(), "zxjh", zxjh)
                        .in(null != xjzt && !xjzt.isEmpty(), "xjzt", xjzt)
                        .in(null != jzbfdxbz && !jzbfdxbz.isEmpty(), "jzbfdxbz", jzbfdxbz)
                        .in(null != knslb && !knslb.isEmpty(), "knslb", knslb)
                        .in(null != hyzk && !hyzk.isEmpty(), "hyzk", hyzk),
                Object::toString);

        if (!StrUtil.isBlank(marketPushParams.getXh())) {
            xhList.addAll(Arrays.stream(marketPushParams.getXh().split(",")).collect(Collectors.toList()));
            xhList = xhList.stream().distinct().collect(Collectors.toList());
        }

        return xhList;
    }

    @Override
    public JsonResult send(MarketPushParams params, Integer loginUserId) {
        // 构造参数
        String content = params.getContent();
        String remark = params.getRemark();

        // 发送学号
        List<String> list = listXh(params);
        int length = list.size();
        if (length == 0) {
            return JsonResult.error("未查询到学生");
        }

        String comment = "";
        // 保存本次推送
        MarketPush marketPush = new MarketPush();
        marketPush.setContent(content);
        marketPush.setRemark(remark);
        marketPush.setNumber(length);
        marketPush.setCreateBy(loginUserId);
        baseMapper.insert(marketPush);

        List<MarketPushRecord> recordAllList = new ArrayList<>();

        String url = wechatUrl + "/mobile/market-push/loading?id=" + marketPush.getId() + "";
        content = "<a href=\"" + url + "\">" + content + "</a>";

        //分2000人推送一次
        int groupSize = 2000;
        //计算可以分成多少组
        int num = (length + groupSize - 1) / groupSize;
        for (int i = 0; i < num; i++) {
            //开始位置
            int fromIndex = i * groupSize;
            //结束位置
            int toIndex = (i + 1) * groupSize < length ? (i + 1) * groupSize : length;
            // 2000一推
            List<String> newList = list.subList(fromIndex, toIndex);
            String[] sends = newList.toArray(new String[newList.size()]);
            JsonResult pushResult = WeChatUtils.push(sends, content);

            comment += JSONUtil.toJsonStr(pushResult.getData()) + "&";

            // 例子
            //String str = "{\"e\":0,\"m\":\"操作成功\",\"d\":{\"ucs_id\":13322049,\"error_data\":{\"1\":\"123*\",\"2\":\"456*\"}}}";
            //JsonResult pushResult = JsonResult.ok().setData(str);

            List<MarketPushRecord> recordList = saveRecord(newList, pushResult, marketPush.getId());
            recordAllList.addAll(recordList);
        }

        // 保存成功失败个数
        long success = recordAllList.stream().filter(d -> d.getState().equals(SUCCESS)).count();
        long fail = recordAllList.stream().filter(d -> d.getState().equals(FAIL)).count();
        marketPush.setSuccess((int) success);
        marketPush.setFail((int) fail);
        marketPush.setComment(comment);
        baseMapper.updateById(marketPush);

        return JsonResult.ok("发送成功");
    }

    /**
     * 保存推送记录
     *
     * @param xhList
     * @param pushResult
     * @param marketPushId
     */
    private List<MarketPushRecord> saveRecord(List<String> xhList, JsonResult pushResult, Integer marketPushId) {
        int code = pushResult.getCode();
        String msg = pushResult.getMsg();

        String e = "";
        String m = "";
        String ucsId = "";
        List<String> errorList = new ArrayList<>();

        if (Constants.RESULT_OK_CODE == code) {
            JSONObject jsonObject = JSONUtil.parseObj(pushResult.getData());
            e = jsonObject.getStr("e");
            m = jsonObject.getStr("m");
            String d = jsonObject.getStr("d");
            if (SUCCESS.equals(e)) {
                JSONObject result = JSONUtil.parseObj(d);
                ucsId = result.getStr("ucs_id");

                String errorData = result.getStr("error_data");
                if (!"[]".equals(errorData)) {
                    JSONObject errorDataJson = JSONUtil.parseObj(errorData);
                    for (int i = 1; i < xhList.size(); i++) {
                        String error = errorDataJson.getStr(i + "");
                        if (!StrUtil.isBlank(error)) {
                            errorList.add(error);
                        } else {
                            break;
                        }
                    }
                }
            }
        }

        List<MarketPushRecord> recordList = new ArrayList<>();
        for (String xh : xhList) {
            MarketPushRecord record = new MarketPushRecord();
            record.setMarketPushId(marketPushId);
            record.setReadState("1");
            record.setXh(xh);
            record.setDescription(m);
            // 整个推送请求错误
            if (Constants.RESULT_ERROR_CODE == code) {
                record.setState(FAIL);
                record.setDescription(msg);
            }

            // 推送请求不成功
            if (!SUCCESS.equals(e)) {
                record.setState(FAIL);
            }

            // 推送请求成功
            if (SUCCESS.equals(e)) {
                record.setState(SUCCESS);
                record.setUcsId(ucsId);
                if (errorList.contains(xh)) {
                    record.setState(FAIL);
                    record.setDescription("不存在或者无对应通讯方式的学工号列表");
                }
            }
            recordList.add(record);
        }
        marketPushRecordService.saveBatch(recordList);
        return recordList;
    }


    @Override
    public void exportExcel(Integer marketPushId, HttpServletResponse response) {
        MarketPush marketPush = baseMapper.selectById(marketPushId);
        List<MarketPushRecordExport> list = marketPushRecordService.exportList(marketPushId);
        for (MarketPushRecordExport item : list) {
            item.setReadState("0".equals(item.getReadState()) ? "已查看" : "未查看");
            item.setState("0".equals(item.getState()) ? "成功" : "失败");
        }

        ExcelWriter writer = ExcelUtil.getWriter(true);

        writer.passCurrentRow();
        writer.passRows(1);
        writer.merge(0, 0, 0, 3, "备注：" + marketPush.getRemark(), false);
        writer.merge(1, 1, 0, 3, "内容：" + marketPush.getContent(), false);

        excelAddHeaderAlias(writer);

        writer.write(list, true);

        // 设置列自适应宽 必须在write以后
        ExcelUtils.autoColumnMaxSizeAll(writer.getSheet());

        String fileName = "record-" + DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN) + ".xlsx";

        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);

        try {
            OutputStream out = response.getOutputStream();
            writer.flush(out, true);
            writer.close();
            IoUtil.close(out);
        } catch (IOException e) {
            writer.close();
        } finally {
            writer.close();
        }
    }

    public void excelAddHeaderAlias(ExcelWriter writer) {
        writer.addHeaderAlias("xh", "学号");
        writer.addHeaderAlias("readState", "查看状态");
        writer.addHeaderAlias("readTime", "查看时间");
        writer.addHeaderAlias("state", "发送状态");
        writer.addHeaderAlias("description", "发送状态描述");
        writer.addHeaderAlias("createTime", "发送时间");
    }
}
